<script setup>
import { useRoute } from 'vue-router'

import {
  convertTabMetadataArr,
  clearOpenedTabDataFromLocalStorage,
  loadOpenedTabDataFromLocalStorage,
  saveOpenedTabDataToLocalStorage,
} from './RouterTabsUtil'
import { computed, onBeforeUnmount, ref, toRefs, watch } from 'vue'
import { Refresh, ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
import { buildWrapperCompNameByRoute } from './CommUtils'

const props = defineProps({
  tabMetadataArr: {
    type: Array,
    default: () => [],
  },
  tabMetadataFieldMapping: {
    type: Object,
    default: () => ({}),
  },
  cardTabType: {
    type: String,
    default: undefined,
  },
  buildTabName: {
    type: Function,
    default: tab => tab.name,
  },
})
const { tabMetadataArr, tabMetadataFieldMapping } = toRefs(props)

/* eslint-disable */
const $emits = defineEmits({
  refresh: (dynRouteName) => true,
  closeAll: (dynCompNameArr, toRoutePath) => true,
  close: (dynRouteName, toRoutePath) => true,
  tabClick: (dynRouteName, toRoutePath) => true,
  closeOther: (
    dynCompName,
    isOperateActiveTab,
    closeAbleOpenedTabIndexArr,
    toPath
  ) => true,
  closeRight: (
    defaultActiveIsClosed,
    closeAbleOpenedTabIndexArr,
    toPath
  ) => true,
})
/* eslint-disable */

const defaultFiledMapping = {
  index: 'index',
  name: 'name',
  icon: 'icon',
  routePath: 'routePath',
  children: 'children',
  customDataMap: 'customDataMap',
  closeAble: 'closeAble',
  keepAlive: 'keepAlive',
}

const fieldMappingComputed = computed(() => {
  return {
    ...defaultFiledMapping,
    ...tabMetadataFieldMapping.value,
  }
})

/**
 * key为TabMetadata的index
 */
const indexTabMetadataMap = computed(() => {
  const retMap = new Map()
  convertTabMetadataArr(
    tabMetadataArr.value,
    retMap,
    fieldMappingComputed.value
  )
  return retMap
})

const tabArr = ref(loadOpenedTabDataFromLocalStorage())
watch(
  tabArr,
  newVal => {
    saveOpenedTabDataToLocalStorage(newVal)
  },
  { immediate: true, deep: true }
)

const openedTabCount = computed(() => (tabArr.value ? tabArr.value.length : 0))

const $route = useRoute()
const defaultActive = ref('')

watch(
  [$route, indexTabMetadataMap],
  ([newRoute, newIndexTabMetadataMap]) => {
    updateTab(newRoute, newIndexTabMetadataMap)
  },
  {
    immediate: true,
  }
)

function updateTab(
  newRoute,
  newIndexTabMetadataMap
) {
  const routeName = newRoute.name 
  if (!routeName) return

  const tabMetadata = newIndexTabMetadataMap.get(routeName)
  if (!tabMetadata) return

  const oldDefaultActive = defaultActive.value
  const openedTabArr = tabArr.value
  const oldActiveIdx = openedTabArr.findIndex(
    item => (item.index ) === oldDefaultActive
  )
  const routeWrapperCompName = buildWrapperCompNameByRoute(newRoute)
  defaultActive.value = routeWrapperCompName
  const index = openedTabArr.findIndex(
    item => item.index === routeWrapperCompName
  )
  if (index < 0) {
    const historyState = window.history.state 
    const baseTab = {
      ...tabMetadata,
      routePath: newRoute.fullPath,
      index: routeWrapperCompName,
      closeAble: newRoute.meta.closeAble === false ? false : true,
      originalRouteName: routeName,
    }
    delete baseTab.children
    if (
      historyState &&
      (historyState.openInSameTab || historyState.replaced) &&
      oldActiveIdx >= 0
    ) {
      openedTabArr[oldActiveIdx] = baseTab
    } else {
      openedTabArr.push(baseTab)
    }
  }
}

function onTabRemove(tabPaneName) {
  closeTab(tabPaneName )
}

function closeTab(dynCompName) {
  const openedTabArr = tabArr.value
  const idx = openedTabArr.findIndex(item => item.index === dynCompName)
  let toRoutePath = undefined
  if (idx >= 0) {
    // 关闭当前标签
    openedTabArr.splice(idx, 1)
    if (defaultActive.value === dynCompName) {
      // 现在关闭的tab是当前处于活动状态的tab
      let tmp
      if (openedTabArr.length === 1) {
        // 关闭当前标签之后，打开的标签只剩一个了，则转入这剩下的这个标签
        tmp = openedTabArr[0]
      } else if (idx - 1 >= 0) {
        // 当前关闭的标签非第一个，则转入当前标签页的上一个位置的标签的路由
        tmp = openedTabArr[idx - 1]
      } else {
        // 当前关闭的标签为第一个，则转入下一个位置标签的路由
        tmp = openedTabArr[idx]
      }
      toRoutePath = tmp.routePath
    }
    $emits('close', dynCompName, toRoutePath)
  }
}

/**
 * 关闭当前tab
 */
function closeCurTab() {
  closeTab(defaultActive.value)
}
function closeAllTab() {
  const openedTabArr = tabArr.value
  let closeAbleOpenedTabIndexArr = openedTabArr
    .filter(item => item.closeAble !== false)
    .map(item => item.index )
  tabArr.value = extractDisableCloseTabArr(
    openedTabArr,
    closeAbleOpenedTabIndexArr
  )
  let toRoutePath
  if (closeAbleOpenedTabIndexArr.includes(defaultActive.value)) {
    // 获取关闭当前tab之后,需要跳转进去的路由地址
    if (tabArr.value.length > 1) {
      toRoutePath = tabArr.value[tabArr.value.length - 1].routePath 
    } else if (tabArr.value.length === 1) {
      toRoutePath = tabArr.value[0].routePath 
    }
  }
  $emits('closeAll', closeAbleOpenedTabIndexArr, toRoutePath)
}

function extractDisableCloseTabArr(
  openedTabArr,
  closeAbleOpenedTabIndexArr
) {
  if (closeAbleOpenedTabIndexArr.length === openedTabArr.length) {
    // 所有tab都可关闭, 则保留第一个不关闭
    return [openedTabArr[0]]
  } else if (closeAbleOpenedTabIndexArr.length !== openedTabArr.length) {
    // 存在不可关闭的tab, 则过滤出剩余不会被关闭的
    return openedTabArr.filter(
      item => !closeAbleOpenedTabIndexArr.includes(item.index)
    )
  } else {
    // 全部都不可关闭
    return openedTabArr
  }
}

function onCloseOther(dynCompName, toPath) {
  const isOperateActiveTab = dynCompName === defaultActive.value
  const openedTabArr = tabArr.value
  let closeAbleOpenedTabIndexArr = openedTabArr
    .filter(item => item.closeAble !== false && item.index !== dynCompName)
    .map(item => item.index )
  tabArr.value = extractDisableCloseTabArr(
    openedTabArr,
    closeAbleOpenedTabIndexArr
  )
  $emits(
    'closeOther',
    dynCompName,
    isOperateActiveTab,
    closeAbleOpenedTabIndexArr,
    toPath
  )
}

function onCloseRight(pos, dynCompName, toPath) {
  const openedTabArr = tabArr.value
  // 获取可关闭的tab索引
  const closeAbleTabIndexArr = openedTabArr
    .filter((item, idx) => idx > pos && item.closeAble !== false)
    .map(item => item.index )
  const activeIsClosed = closeAbleTabIndexArr.includes(defaultActive.value)
  tabArr.value = extractDisableCloseTabArr(openedTabArr, closeAbleTabIndexArr)
  $emits('closeRight', activeIsClosed, closeAbleTabIndexArr, toPath)
}

function onTabClick({ paneName }) {
  const openedTabArr = tabArr.value
  const idx = openedTabArr.findIndex(item => item.index === paneName)
  if (idx >= 0) {
    const { routePath } = openedTabArr[idx]
    $emits('tabClick', paneName , routePath)
  } else {
    $emits('tabClick', paneName )
  }
}

function onRefresh() {
  const dynCompName = buildWrapperCompNameByRoute($route)
  $emits('refresh', dynCompName)
}
// 该key用于解决el-tabs的标签无法重新排序问题
const elTabKey = ref<number>(1)

function onMoveToLeft(pos) {
  if (pos > 0) {
    const tmpArr = [...tabArr.value]
    const tmp = tmpArr[pos - 1]
    tmpArr[pos - 1] = tmpArr[pos]
    tmpArr[pos] = tmp
    tabArr.value = tmpArr
    elTabKey.value += 1
  }
}
function onMoveToRight(pos) {
  const tmpArr = [...tabArr.value]
  const len = tmpArr.length
  if (pos < len - 1) {
    const tmp = tmpArr[pos + 1]
    tmpArr[pos + 1] = tmpArr[pos]
    tmpArr[pos] = tmp
    tabArr.value = tmpArr
    elTabKey.value += 1
  }
}
const dropdownRef = ref()
function handleChange(visible, name) {
  if (!visible) return
  dropdownRef.value.forEach((item) => {
    if (item.id === name) return
    item.handleClose()
  })
}
onBeforeUnmount(() => {
  clearOpenedTabDataFromLocalStorage()
})

defineExpose({
  closeAllTab,
  closeTab,
  closeCurTab,
})
</script>

<template>
  <div class="flex flex-row h-full">
    <div class="flex-1 w-0">
      <el-tabs
        class="o-archetype-tabs"
        :key="elTabKey"
        :model-value="defaultActive"
        :type="cardTabType"
        @tab-remove="onTabRemove"
        @tab-click="onTabClick"
      >
        <template v-if="!$slots.label">
          <el-tab-pane
            v-for="(item, pos) in tabArr"
            :key="item.index"
            :label="props.buildTabName(item)"
            :name="item.index"
            :closable="item.closeAble && tabArr.length > 1"
          >
            <template #label>
              <el-dropdown
                :id="`_dropdown-${item.index}`"
                ref="dropdownRef"
                trigger="contextmenu"
                @visible-change="
                  handleChange($event, `_dropdown-${item.index }`)
                "
              >
                <span class="o-tab-item-title pl-1 pr-1">
                  {{ props.buildTabName(item) }}
                </span>
                <template #dropdown>
                  <el-dropdown-menu>
                    <el-dropdown-item
                      v-if="defaultActive === item.index"
                      @click="onRefresh"
                    >
                      <el-icon class="mr-1 ml-1"> <Refresh /> </el-icon>
                      刷新
                    </el-dropdown-item>
                    <el-dropdown-item
                      @click="
                        onCloseOther(item.index , item.routePath)
                      "
                    >
                      <el-icon class="mr-1 ml-1">&nbsp;</el-icon>关闭其他标签页
                    </el-dropdown-item>
                    <el-dropdown-item
                      @click="
                        onCloseRight(pos, item.index , item.routePath)
                      "
                    >
                      <el-icon class="mr-1 ml-1">&nbsp;</el-icon>关闭右侧标签页
                    </el-dropdown-item>
                    <el-dropdown-item @click="onMoveToLeft(pos)">
                      <el-icon class="mr-1 ml-1"> <ArrowLeft /> </el-icon>
                      标签左移
                    </el-dropdown-item>
                    <el-dropdown-item @click="onMoveToRight(pos)">
                      <el-icon class="mr-1 ml-1"><ArrowRight /></el-icon
                      >标签右移
                    </el-dropdown-item>
                  </el-dropdown-menu>
                </template>
              </el-dropdown>
            </template>
          </el-tab-pane>
        </template>
        <template v-else>
          <el-tab-pane
            v-for="item in tabArr"
            :key="item.index"
            :name="item.index"
          >
            <template #label>
              <slot
                name="label"
                :item="item"
                :cur-tab="defaultActive"
                :opened-tab-count="openedTabCount"
              ></slot>
            </template>
          </el-tab-pane>
        </template>
      </el-tabs>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.o-archetype-tabs {
  ::v-deep(.el-tabs__header) {
    margin-bottom: 0;
  }
  ::v-deep(.el-tabs__nav-wrap:after) {
    display: none;
  }
  ::v-deep(.el-tabs__active-bar) {
    display: none;
  }
  ::v-deep(.el-tabs__item) {
    padding-left: 0.75rem !important;
    padding-right: 0.75rem !important;
    .o-tab-item-title {
      color: rgba(0, 0, 0, 0.92);
      transition: color 0.3s 0.1s;
    }
    &:hover {
      color: var(--primaryColor);
      .o-tab-item-title {
        color: var(--primaryColor);
      }
    }
  }
  ::v-deep(.el-tabs__item.is-active) {
    background-color: var(--primaryBgColor);
    .o-tab-item-title {
      color: var(--primaryColor);
    }
  }
}
</style>
